home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_xemacs.idb / usr / freeware / lib / xemacs-20.4 / lisp / ilisp / completer.el.z / completer.el
Encoding:
Text File  |  1998-05-21  |  35.4 KB  |  1,027 lines

  1. ;;; -*-Emacs-Lisp-*-
  2. ;;;%Header
  3. ;;;
  4. ;;; Rcs_Info: completer.el,v 3.23 1993/09/03 02:05:07 ivan Rel $
  5. ;;;
  6. ;;; Partial completion mechanism for GNU Emacs.  Version 3.03
  7. ;;; Copyright (C) 1990, 1991, 1992 Chris McConnell, ccm@cs.cmu.edu.
  8. ;;; Thanks to Bjorn Victor for suggestions, testing, and patches for
  9. ;;; file completion. 
  10.  
  11. ;;; This file is part of GNU Emacs.
  12.  
  13. ;;; GNU Emacs is distributed in the hope that it will be useful,
  14. ;;; but WITHOUT ANY WARRANTY.  No author or distributor
  15. ;;; accepts responsibility to anyone for the consequences of using it
  16. ;;; or for whether it serves any particular purpose or works at all,
  17. ;;; unless he says so in writing.  Refer to the GNU Emacs General Public
  18. ;;; License for full details.
  19. ;;; Everyone is granted permission to copy, modify and redistribute
  20. ;;; GNU Emacs, but only under the conditions described in the
  21. ;;; GNU Emacs General Public License.   A copy of this license is
  22. ;;; supposed to have been given to you along with GNU Emacs so you
  23. ;;; can know your rights and responsibilities.  It should be in a
  24. ;;; file named COPYING.  Among other things, the copyright notice
  25. ;;; and this notice must be preserved on all copies.
  26.  
  27. ;;; When loaded, this file extends the standard completion mechanisms
  28. ;;; so that they perform pattern matching completions.  There is also
  29. ;;; an interface that allows it to be used by other programs.  The
  30. ;;; completion rules are:
  31. ;;;
  32. ;;; 1) If what has been typed matches any possibility, do normal
  33. ;;; completion. 
  34. ;;;
  35. ;;; 2) Otherwise, generate a regular expression such that
  36. ;;; completer-words delimit words and generate all possible matches.
  37. ;;; The variable completer-any-delimiter can be set to a character
  38. ;;; that matches any delimiter.  If it were " ", then "by  d" would be 
  39. ;;; byte-recompile-directory.  If completer-use-words is T, a match is
  40. ;;; unique if it is the only one with the same number of words.  If
  41. ;;; completer-use-words is NIL, a match is unique if it is the only
  42. ;;; possibility.  If you ask the completer to use its best guess, it
  43. ;;; will be the shortest match of the possibilities unless
  44. ;;; completer-exact is T.
  45. ;;;
  46. ;;; 3) For filenames, if completer-complete-filenames is T, each
  47. ;;; pathname component will be individually completed, otherwise only
  48. ;;; the final component will be completed.  If you are using a
  49. ;;; distributed file system like afs, you may want to set up a
  50. ;;; symbolic link in your home directory or add pathname components to
  51. ;;; completer-file-skip so that the pathname components that go across
  52. ;;; machines do not get expanded.
  53. ;;;
  54. ;;; SPACE, TAB, LFD, RET, and ? do normal completion if possible
  55. ;;; otherwise they do partial completion.  In addition, C-DEL will
  56. ;;; undo the last partial expansion or contraction.  M-RET will always
  57. ;;; complete to the current match before returning.  This is useful
  58. ;;; when any string is possible, but you want to complete to a string
  59. ;;; as when calling find-file.  The bindings can be changed by using
  60. ;;; completer-load-hook.
  61. ;;;
  62. ;;; Modes that use comint-dynamic-complete (like cmushell and ilisp)
  63. ;;; will also do partial completion as will M-tab in Emacs LISP.
  64. ;;;
  65. ;;; Examples:
  66. ;;; a-f     auto-fill-mode
  67. ;;; b--d    *beginning-of-defun or byte-recompile-directory
  68. ;;; by  d   *byte-recompile-directory if completer-any-delimiter is " "
  69. ;;; ~/i.e   *~/ilisp.el or ~/il-el.el or ~/ilisp.elc
  70. ;;; /u/mi/  /usr/misc/
  71. ;;;
  72.  
  73.  
  74. (require 'cl)
  75.  
  76. ;;;%Globals
  77. ;;;%%Switches
  78. (defvar completer-load-hook nil
  79.   "Hook called when minibuffer partial completion is loaded.")
  80.  
  81. (defvar completer-disable nil
  82.   "*If T, turn off partial completion.  Use the command
  83. \\[completer-toggle] to set this.")
  84.  
  85. (defvar completer-complete-filenames t
  86.   "*If T, then each component of a filename will be completed,
  87. otherwise just the final component will be completed.")
  88.  
  89. (defvar completer-use-words nil ; jwz: this is HATEFUL!
  90.   "*If T, then prefer completions with the same number of words as the
  91. pattern.")
  92.  
  93. (defvar completer-words "---. <" 
  94.   "*Delimiters used in partial completions.  It should be a set of
  95. characters suitable for inclusion in a [] regular expression.")
  96.  
  97. (defvar completer-any-delimiter nil
  98.   "*If a character, then a delimiter in the pattern that matches the
  99. character will match any delimiter in completer-words.")
  100.  
  101. (defvar completer-file-skip "^cs/$\\|@sys\\|.edu/$\\|.gov/$\\|.com/$\\|:/$"
  102.   "*Regular expression for pathname components to not complete.")
  103.  
  104. (defvar completer-exact nil
  105.   "*If T, then you must have an exact match.  Otherwise, the shortest
  106. string that matches the pattern will be used.")
  107.  
  108. (defvar completer-cache-size 100
  109.   "*Size of cache to use for partially completed pathnames.")
  110.  
  111. (defvar completer-use-cache t
  112.   "*Set to nil to disable the partially completed pathname cache.")
  113.  
  114. ;;;%%Internal
  115. (defvar completer-last-pattern ""
  116.   "The last pattern expanded.")
  117.  
  118. (defvar completer-message nil
  119.   "T if temporary message was just displayed.")
  120.  
  121. (defvar completer-path-cache nil
  122.   "Cache of (path . choices) for completer.")
  123.  
  124. (defvar completer-string nil "Last completer string.")
  125. (defvar completer-table nil "Last completer table.")
  126. (defvar completer-pred nil "Last completer pred.")
  127. (defvar completer-mode nil "Last completer mode.")
  128. (defvar completer-result nil "Last completer result.")
  129.  
  130. (eval-when (eval load compile)
  131.   (if (not (fboundp 'completion-display-completion-list-function))
  132.       (setf completion-display-completion-list-function
  133.         'display-completion-list)))
  134.  
  135.  
  136. ;;;%Utilities
  137. (defun completer-message (message &optional point)
  138.   "Display MESSAGE at optional POINT for two seconds."
  139.   (setq point (or point (point-max))
  140.     completer-message t)
  141.   (let ((end
  142.      (save-excursion
  143.        (goto-char point)
  144.        (insert message)
  145.        (point)))
  146.     (inhibit-quit t))
  147.     (sit-for 2)
  148.     (delete-region point end)
  149.     (if (and quit-flag 
  150.          ;;(not (eq 'lucid-19 ilisp-emacs-version-id))
  151.          (not (string-match "Lucid" emacs-version))
  152.          )
  153.     (setq quit-flag nil
  154.           unread-command-char 7))))
  155.  
  156. ;;;
  157. (defun completer-deleter (regexp choices &optional keep)
  158.   "Destructively remove strings that match REGEXP in CHOICES and
  159. return the modified list.  If optional KEEP, then keep entries that
  160. match regexp."
  161.   (let* ((choiceb choices)
  162.      choicep)
  163.     (if keep
  164.     (progn
  165.       (while (and choiceb (not (string-match regexp (car choiceb))))
  166.         (setq choiceb (cdr choiceb)))
  167.       (setq choicep choiceb)
  168.       (while (cdr choicep)
  169.         (if (string-match regexp (car (cdr choicep)))
  170.         (setq choicep (cdr choicep))
  171.         (rplacd choicep (cdr (cdr choicep))))))
  172.     (while (and choiceb (string-match regexp (car choiceb)))
  173.       (setq choiceb (cdr choiceb)))
  174.     (setq choicep choiceb)
  175.     (while (cdr choicep)
  176.       (if (string-match regexp (car (cdr choicep)))
  177.           (rplacd choicep (cdr (cdr choicep)))
  178.           (setq choicep (cdr choicep)))))
  179.     choiceb))
  180.  
  181. ;;;%%Regexp
  182. (defun completer-regexp (string delimiters any)
  183.   "Convert STRING into a regexp with words delimited by characters in
  184. DELIMITERS.  Any delimiter in STRING that is the same as ANY will
  185. match any delimiter."
  186.   (let* ((delimiter-reg (concat "[" delimiters "]"))
  187.      (limit (length string))
  188.      (pos 0)
  189.      (regexp "^"))
  190.     (while (and (< pos limit) (string-match delimiter-reg string pos))
  191.       (let* ((begin (match-beginning 0))
  192.          (end (match-end 0))
  193.          (delimiter (substring string begin end))
  194.          (anyp (eq (elt string begin) any)))
  195.     (setq regexp 
  196.           (format "%s%s[^%s]*%s" 
  197.               regexp
  198.               (regexp-quote (substring string pos begin))
  199.               (if anyp delimiters delimiter)
  200.               (if anyp delimiter-reg (regexp-quote delimiter)))
  201.           pos end)))
  202.     (if (<= pos limit)
  203.     (setq regexp (concat regexp 
  204.                  (regexp-quote (substring string pos limit)))))))
  205.  
  206. ;;;
  207. (defun completer-words (regexp string &optional limit)
  208.   "Return the number of words matching REGEXP in STRING up to LIMIT."
  209.   (setq limit (or limit 1000))
  210.   (let ((count 1)
  211.     (pos 0))
  212.     (while (and (string-match regexp string pos) (<= count limit))
  213.       (setq count (1+ count)
  214.         pos (match-end 0)))
  215.     count))
  216.  
  217. ;;;%Matcher
  218. (defun completer-matches (string choices delimiters any)
  219.     "Return STRING's matches in CHOICES using DELIMITERS and wildcard
  220. ANY to segment the strings."
  221.     (let* ((regexp (concat "[" delimiters "]"))
  222.        (from nil)
  223.        (to 0)
  224.        (pattern nil)
  225.        (len (length string))
  226.        (matches nil)
  227.        sub sublen choice word wordlen pat)
  228.       ;; Segment pattern
  229.       (while (< (or from 0) len)
  230.     (setq to (or (string-match regexp string (if from (1+ from))) len))
  231.     (if (eq (elt string (or from 0)) completer-any-delimiter)
  232.         (setq sub (substring string (if from (1+ from) 0) to)
  233.           sublen (- (length sub)))
  234.         (setq sub (substring string (or from 0) to)
  235.           sublen (length sub)))
  236.     (setq pattern (cons (cons sub sublen) pattern)
  237.           from to))
  238.       (setq pattern (reverse pattern))
  239.       ;; Find choices that match patterns
  240.       (setq regexp (concat "[" delimiters "]"))
  241.       (while choices
  242.     (setq choice (car choices)
  243.           word pattern 
  244.           from 0)
  245.     (while (and word from
  246.             (let* (begin end)
  247.               (if (< (setq wordlen (cdr (setq pat (car word)))) 0)
  248.               (setq begin (1+ from)
  249.                 end (+ begin (- wordlen)))
  250.               (setq begin from
  251.                 end (+ begin wordlen)))
  252.               (and (<= end (length choice))
  253.                (or (zerop wordlen)
  254.                    (string-equal 
  255.                 (car pat)
  256.                 (substring choice begin end))))))
  257.       (setq from (string-match regexp choice 
  258.                    (if (and (zerop from) (zerop wordlen))
  259.                        from
  260.                        (1+ from)))
  261.         word (cdr word)))
  262.     (if (not word) (setq matches (cons choice matches)))
  263.     (setq choices (cdr choices)))
  264.       matches))
  265.  
  266. ;;;
  267. (defun completer-choice (string choices delimiters use-words)
  268.   "Return the best match of STRING in CHOICES with DELIMITERS between
  269. words and T if it is unique.  A match is unique if it is the only
  270. possibility or when USE-WORDS the only possibility with the same
  271. number of words.  The shortest string of multiple possibilities will be
  272. the best match."
  273.   (or (if (null (cdr choices)) (cons (car choices) t))
  274.       (let* ((regexp (concat "[^" delimiters "]*[" delimiters "]"))
  275.          (words (if use-words (completer-words regexp string)))
  276.          (choice choices)
  277.          (unique-p nil)
  278.          (match nil)
  279.          (match-count nil)
  280.          (match-len 1000))
  281.     (while choice
  282.       (let* ((current (car choice))
  283.          (length (length current)))
  284.         (if match-count
  285.         (if (= (completer-words regexp current words) words)
  286.             (progn
  287.               (setq unique-p nil)
  288.               (if (< length match-len)
  289.               (setq match current
  290.                 match-len length))))
  291.         (if (and use-words 
  292.              (= (completer-words regexp current words) words))
  293.             (setq match current
  294.               match-len length
  295.               match-count t
  296.               unique-p t)
  297.             (if (< length match-len)
  298.             (setq match current
  299.                   match-len length)))))
  300.       (setq choice (cdr choice)))
  301.     (cons match unique-p))))
  302.  
  303. ;;;%Completer
  304. ;;;%%Utilities
  305. (defun completer-region (delimiters)
  306.   "Return the completion region bounded by characters in DELIMITERS
  307. for the current buffer assuming that point is in it."
  308.   (cons (save-excursion (skip-chars-backward delimiters) (point))
  309.     (save-excursion (skip-chars-forward delimiters) (point))))
  310.      
  311. ;;;
  312. (defun completer-last-component (string)
  313.   "Return the start of the last filename component in STRING."
  314.   (let ((last (1- (length string)) )
  315.     (match 0)
  316.     (end 0))
  317.     (while (and (setq match (string-match "/" string end)) (< match last))
  318.       (setq end (1+ match)))
  319.     end))
  320.  
  321. ;;;
  322. (defun completer-match-record (string matches delimiters any dir mode)
  323.   "Return (match lcs choices unique) for STRING in MATCHES with
  324. DELIMITERS or ANY wildcards and DIR if a filename when in MODE."
  325.   (let ((pattern (if dir
  326.              (substring string (completer-last-component string))
  327.              string))
  328.     match)
  329.     (setq matches (completer-matches pattern matches delimiters any)
  330.       match (try-completion pattern (mapcar 'list matches)))
  331.     ;; If try-completion produced an exact match for an element in 'matches',
  332.     ;; then remove any partial matches from 'matches' and set the unique
  333.     ;; match flag.
  334.     (and (stringp match) (member match matches) (setq matches (list match)))
  335.     (if (cdr matches)
  336.     (let ((lcs (concat dir (try-completion "" (mapcar 'list matches)))))
  337.       (setq match (if (not completer-exact)
  338.               (completer-choice
  339.                pattern matches delimiters completer-use-words)))
  340.       (list (if match (concat dir (car match)))
  341.         lcs
  342.         matches
  343.         (cdr match)))
  344.       (if matches
  345.       (progn (setq match (concat dir (car matches)))
  346.          (list match match matches t))
  347.     (list nil nil nil nil)))))
  348.  
  349. ;;;%%Complete file
  350. (defun completer-extension-regexp (extensions)
  351.   "Return a regexp that matches to a string that ends with any string from EXTENSIONS list."
  352.   (concat "\\(" (mapconcat 'regexp-quote extensions "\\|") "\\)\\'"))
  353.  
  354. ;;;
  355. (defun completer-flush ()
  356.   "Flush completer's pathname cache."
  357.   (interactive)
  358.   (setq completer-path-cache nil))
  359.  
  360. ;;;
  361. (defun completer-cache (path pred words any mode)
  362.   "Check to see if PATH is in path cache with PRED, WORDS, ANY and
  363. MODE."
  364.   (let* ((last nil)
  365.      (ptr completer-path-cache)
  366.      (size 0) 
  367.      (result nil))
  368.     (if completer-use-cache
  369.     (while ptr
  370.       (let ((current (car (car ptr))))
  371.         (if (string-equal current path)
  372.         (progn
  373.           (if last
  374.               (progn
  375.             (rplacd last (cdr ptr))
  376.             (rplacd ptr completer-path-cache)
  377.             (setq completer-path-cache ptr)))
  378.           (setq result (cdr (car ptr))
  379.             ptr nil))
  380.           (if (cdr ptr) (setq last ptr))
  381.           (setq size (1+ size)
  382.             ptr (cdr ptr))))))
  383.     (or result
  384.     (let* ((choices 
  385.         (completer path 'read-file-name-internal pred words any
  386.                mode t)))
  387.       (if (and (or (car (cdr (cdr (cdr choices))))
  388.                (string= path (car choices)))
  389.            (eq (elt (car choices) (1- (length (car choices)))) ?/))
  390.           (progn 
  391.         (if (>= size completer-cache-size) (rplacd last nil))
  392.         (setq completer-path-cache 
  393.               (cons (cons path choices) completer-path-cache))))
  394.       choices))))
  395.  
  396. ;;;
  397. (defun completer-file (string pred words any mode)
  398.   "Return (match common-substring matches unique-p) for STRING using
  399. read-file-name-internal for choices that pass PRED using WORDS to
  400. delimit words.  Optional ANY is a delimiter that matches any of the
  401. delimiters in WORD.  If optional MODE is nil or 'help then possible
  402. matches will always be returned."
  403.   (let* ((case-fold-search completion-ignore-case)
  404.      (last (and (eq mode 'exit-ok) (completer-last-component string)))
  405.      (position
  406.       ;; Special hack for CMU RFS filenames
  407.       (if (string-match "^/\\.\\./[^/]*/" string)
  408.           (match-end 0)
  409.           (string-match "[^~/]" string)))
  410.      (new (substring string 0 position))
  411.      (user (if (string= new "~")
  412.            (setq new (file-name-directory (expand-file-name new)))))
  413.      (words (concat words "/"))
  414.      (len (length string))
  415.      (choices nil)
  416.      end
  417.      (old-choices (list nil nil nil nil)))
  418.     (while position
  419.       (let* ((begin (string-match "/" string position))
  420.          (exact-p nil))
  421.     (setq end (if begin (match-end 0))
  422.           choices
  423.           ;; Ends with a /, so check files in directory
  424.           (if (and (memq mode '(nil help)) (= position len))
  425.           (completer-match-record 
  426.            ""
  427.            ;; This assumes that .. and . come at the end
  428.            (let* ((choices
  429.                (all-completions new 'read-file-name-internal))
  430.               (choicep choices))
  431.              (if (string= (car choicep) "../")
  432.              (cdr (cdr choicep))
  433.              (while (cdr choicep)
  434.                (if (string= (car (cdr choicep)) "../")
  435.                    (rplacd choicep nil))
  436.                (setq choicep (cdr choicep)))
  437.              choices))
  438.            words any new mode)
  439.           (if (eq position last)
  440.               (let ((new (concat new (substring string position))))
  441.             (list new new nil t))
  442.               (let ((component (substring string position end)))
  443.             (if (and end
  444.                  (string-match completer-file-skip component))
  445.                 ;; Assume component is complete
  446.                 (list (concat new component) 
  447.                   (concat new component)
  448.                   nil t)
  449.                 (completer-cache
  450.                  (concat new component)
  451.                  pred words any mode))))))
  452.     ;; Keep going if unique or we match exactly
  453.     (if (or (car (cdr (cdr (cdr choices))))
  454.         (setq exact-p
  455.               (string= (concat new (substring string position end))
  456.                    (car choices))))
  457.         (setq old-choices
  458.           (let* ((lcs (car (cdr choices)))
  459.              (matches (car (cdr (cdr choices))))
  460.              (slash (and lcs (string-match "/$" lcs))))
  461.             (list nil
  462.               (if slash (substring lcs 0 slash) lcs)
  463.               (if (and (cdr matches) 
  464.                    (or (eq mode 'help) (not exact-p)))
  465.                   matches)
  466.               nil))
  467.           new (car choices)
  468.           position end)
  469.         ;; Its ok to not match user names because they may be in
  470.         ;; different root directories
  471.         (if (and (= position 1) (= (elt string 0) ?~))
  472.         (setq new (substring string 0 end)
  473.               choices (list new new (list new) t)
  474.               user nil
  475.               position end)
  476.         (setq position nil)))))
  477.     (if (not (car choices))
  478.     (setq choices old-choices))
  479.     (if (and (car choices)
  480.          (not (eq mode 'help))
  481.          (not (car (cdr (cdr (cdr choices))))))
  482.     ;; Try removing completion ignored extensions
  483.     (let* ((extensions
  484.         (completer-extension-regexp completion-ignored-extensions))
  485.            (choiceb (car (cdr (cdr choices))))
  486.            (choicep choiceb)
  487.            (isext nil)
  488.            (noext nil))
  489.       (while choicep
  490.         (if (string-match extensions (car choicep))
  491.         (setq isext t)
  492.         (setq noext t))
  493.         (if (and isext noext)
  494.         ;; There are matches besides extensions
  495.         (setq choiceb (completer-deleter extensions choiceb)
  496.               choicep nil)
  497.         (setq choicep (cdr choicep))))
  498.       (if (and isext noext)
  499.           (setq choices
  500.             (completer-match-record 
  501.              (if end (substring string end) "")
  502.              choiceb words any
  503.              (file-name-directory (car (cdr choices)))
  504.              mode)))))
  505.     (if user
  506.     (let ((match (car choices))
  507.           (lcs (car (cdr choices)))
  508.           (len (length user)))
  509.       (setq choices
  510.         (cons (if match (concat "~" (substring match len)))
  511.               (cons (if lcs (concat "~" (substring lcs len)))
  512.                 (cdr (cdr choices)))))))
  513.     choices))
  514.  
  515. ;;;%Exported program interface
  516. ;;;%%Completer
  517. (defun completer (string table pred words
  518.              &optional any mode file-p)
  519.   "Return (match common-substring matches unique-p) for STRING in
  520. TABLE for choices that pass PRED using WORDS to delimit words.  If the
  521. flag completer-complete-filenames is T and the table is
  522. read-file-name-internal, then filename components will be individually
  523. expanded.  Optional ANY is a delimiter that can match any delimiter in
  524. WORDS.  Optional MODE is nil for complete, 'help for help and 'exit
  525. for exit."
  526.   (if (and (stringp completer-string) 
  527.        (string= string completer-string)
  528.        (eq table completer-table)
  529.        (eq pred completer-pred)
  530.        (not file-p)
  531.        (or (eq mode completer-mode)
  532.            (not (memq table '(read-file-name-internal
  533.                   read-directory-name-internal)))))
  534.       completer-result
  535.       (setq 
  536.        completer-string ""
  537.        completer-table table
  538.        completer-pred pred
  539.        completer-mode mode
  540.        completer-result
  541.        (if (and completer-complete-filenames
  542.         (not file-p) (eq table 'read-file-name-internal))
  543.        (completer-file string pred words any mode)
  544.        (let* ((file-p (or file-p (eq table 'read-file-name-internal)))
  545.           (case-fold-search completion-ignore-case)
  546.           (pattern (concat "[" words "]"))
  547.           (component (if file-p (completer-last-component string)))
  548.           (dir (if component (substring string 0 component)))
  549.           (string (if dir (substring string component) string))
  550.           (has-words (or (string-match pattern string)
  551.                  (length string))))
  552.          (if (and file-p (string-match "^\\$" string))
  553.          ;; Handle environment variables
  554.          (let ((match
  555.             (getenv (substring string 1 
  556.                        (string-match "/" string)))))
  557.            (if match (setq match (concat match "/")))
  558.            (list match match (list match) match))
  559.          (let* ((choices
  560.              (all-completions 
  561.               (concat dir (substring string 0 has-words))
  562.               table pred))
  563.             (regexp (completer-regexp string words any)))
  564.            (if choices
  565.                (completer-match-record 
  566.             string 
  567.             (completer-deleter regexp choices t) 
  568.             words any dir mode)
  569.                (list nil nil nil nil))))))
  570.        completer-string string)
  571.       completer-result))
  572.  
  573. ;;;%%Display choices
  574. (defun completer-display-choices (choices &optional match message end
  575.                       display)
  576.   "Display the list of possible CHOICES with optional MATCH, MESSAGE,
  577. END and DISPLAY.  If MATCH is non-nil, it will be flagged as the best
  578. guess.  If there are no choices, display MESSAGE.  END is where to put
  579. temporary messages.  If DISPLAY is present then it will be called on
  580. each possible completion and should return a string."
  581.   (if choices
  582.       (with-output-to-temp-buffer "*Completions*"
  583.     (if (cdr choices) 
  584.         (funcall completion-display-completion-list-function
  585.          (sort
  586.           (if display
  587.           (let ((old choices)
  588.             (new nil))
  589.             (while old
  590.               (setq new (cons (funcall display (car old)) new)
  591.                 old (cdr old)))
  592.             new)
  593.         (copy-sequence choices))
  594.           (function (lambda (x y)
  595.               (string-lessp (or (car-safe x) x)
  596.                     (or (car-safe y) y)))))))
  597.     (if match
  598.         (save-excursion
  599.           (set-buffer "*Completions*")
  600.           (goto-char (point-min))
  601.           (let ((buffer-read-only nil))
  602.         (insert "Guess = " match (if (cdr choices) ", " "") "\n")))))
  603.       (beep)
  604.       (completer-message (or message " (No completions)") end)))
  605.  
  606. ;;;%%Goto
  607. (defun completer-goto (match lcs choices unique delimiters words 
  608.                  &optional mode display)
  609.   "MATCH is the best match, LCS is the longest common substring of all
  610. of the matches.  CHOICES is a list of the possibilities, UNIQUE
  611. indicates if MATCH is unique.  DELIMITERS are possible bounding
  612. characters for the completion region.  WORDS are the characters that
  613. delimit the words for partial matches.  Replace the region bounded by
  614. delimiters with the match if unique and the lcs otherwise unless
  615. optional MODE is 'help.  Then go to the part of the string that
  616. disambiguates choices using WORDS to separate words and display the
  617. possibilities if the string was not extended.  If optional DISPLAY is
  618. present then it will be called on each possible completion and should
  619. return a string."
  620.   (setq completer-message nil)
  621.   (let* ((region (completer-region delimiters))
  622.      (start (car region))
  623.      (end (cdr region))
  624.      (string (buffer-substring start end))
  625.      (file-p (string-match "[^ ]*\\(~\\|/\\|$\\)" string))
  626.      (no-insert (eq mode 'help))
  627.      (message t)
  628.      (new (not (string= (buffer-substring start (point)) lcs))))
  629.     (if unique
  630.     (if no-insert
  631.         (progn
  632.           (goto-char end)
  633.           (completer-display-choices choices match nil end display))
  634.         (if (string= string match)
  635.         (if (not file-p) 
  636.             (progn (goto-char end)
  637.                (completer-message " (Sole completion)" end)))
  638.         (completer-insert match delimiters)))
  639.     ;;Not unique
  640.     (if lcs
  641.         (let* ((regexp 
  642.             (concat "[" words (if file-p "/") "]"))
  643.            (words (completer-words regexp lcs))
  644.            point)
  645.           ;; Go to where its ambiguous
  646.           (goto-char start)
  647.           (if (not no-insert)
  648.           (progn 
  649.             (insert lcs)
  650.             (setq completer-last-pattern 
  651.               (list string delimiters (current-buffer) start)
  652.               start (point)
  653.               end (+ end (length lcs)))))
  654.           ;; Skip to the first delimiter in the original string
  655.           ;; beyond the ambiguous point and keep from there on
  656.           (if (re-search-forward regexp end 'move words)
  657.           (progn
  658.             (if (and (not no-insert) match)
  659.             (let ((delimiter
  660.                    (progn
  661.                  (string-match (regexp-quote lcs) match)
  662.                  (substring match (match-end 0)
  663.                         (1+ (match-end 0))))))
  664.               (if (string-match regexp delimiter)
  665.                   (insert delimiter))))
  666.             (forward-char -1)))
  667.           (if (not no-insert) 
  668.           (progn
  669.             (setq end (- end (- (point) start)))
  670.             (delete-region start (point))))))
  671.     (if choices
  672.         (if (or no-insert (not new))
  673.         (completer-display-choices choices match nil end display))
  674.         (if file-p 
  675.         (progn 
  676.           (if (not (= (point) end)) (forward-char 1))
  677.           (if (not (save-excursion (re-search-forward "/" end t)))
  678.               (goto-char end))))
  679.         (if message
  680.         (progn
  681.           (beep)
  682.           (completer-message (if no-insert 
  683.                      " (No completions)"
  684.                      " (No match)")
  685.                      end)))))))        
  686.  
  687. ;;;%Exported buffer interface
  688. ;;;%%Complete and go
  689. (defun completer-complete-goto (delimiters words table pred 
  690.                        &optional no-insert display)
  691.   "Complete the string bound by DELIMITERS using WORDS to bound words
  692. for partial matches in TABLE with PRED and then insert the longest
  693. common substring unless optional NO-INSERT and go to the point of
  694. ambiguity.  If optional DISPLAY, it will be called on each match when
  695. possible completions are shown and should return a string."
  696.   (let* ((region (completer-region delimiters)))
  697.     (apply 'completer-goto 
  698.        (append (completer (buffer-substring (car region) (cdr region))
  699.                   table pred words completer-any-delimiter
  700.                   no-insert)
  701.           (list delimiters words no-insert display)))))
  702.  
  703. ;;;%%Undo
  704. (defun completer-insert (match delimiters &optional buffer undo)
  705.   "Replace the region bounded with characters in DELIMITERS by MATCH
  706. and save it so that it can be restored by completer-undo."
  707.   (let* ((region (completer-region delimiters))
  708.      (start (car region))
  709.      (end (cdr region)))
  710.     (if (and undo (or (not (= start undo)) 
  711.               (not (eq (current-buffer) buffer))))
  712.     (error "No previous pattern")
  713.     (setq completer-last-pattern (list (buffer-substring start end) 
  714.                        delimiters
  715.                        (current-buffer)
  716.                        start))
  717.     (delete-region start end)
  718.     (goto-char start)
  719.     (insert match))))
  720.  
  721. ;;;
  722. (defun completer-undo ()
  723.   "Swap the last expansion and the last match pattern."
  724.   (interactive)
  725.   (if completer-last-pattern
  726.       (apply 'completer-insert completer-last-pattern)
  727.       (error "No previous pattern")))
  728.  
  729. ;;;%Minibuffer specific code
  730. ;;;%%Utilities
  731. (defun completer-minibuf-string ()
  732.   "Remove dead filename specs from the minibuffer as delimited by //
  733. or ~ or $ and return the resulting string."
  734.   (save-excursion
  735.     (goto-char (point-max))
  736.     (if (and (eq minibuffer-completion-table 'read-file-name-internal)
  737.          (re-search-backward "//\\|/~\\|.\\$" nil t))
  738.     (delete-region (point-min) (1+ (point))))
  739.     (buffer-substring (point-min) (point-max))))
  740.  
  741. ;;;
  742. (defun completer-minibuf-exit ()
  743.   "Exit the minibuffer and clear completer-last-pattern."
  744.   (interactive)
  745.   (setq completer-last-pattern nil)
  746.   (exit-minibuffer))
  747.  
  748. ;;;
  749. (defun completer-new-cmd (cmd)
  750.   "Return T if we can't execute the old minibuffer version of CMD."
  751.   (if (or completer-disable
  752.       (let ((string (completer-minibuf-string)))
  753.         (or
  754.          (not (string-match
  755.            (concat "[" completer-words "/~]")
  756.            string))
  757.           (condition-case ()
  758.           (let ((completion
  759.              (try-completion string
  760.                      minibuffer-completion-table
  761.                      minibuffer-completion-predicate)))
  762.             (if (eq minibuffer-completion-table
  763.                 'read-file-name-internal)
  764.             ;; Directories complete as themselves
  765.             (and completion
  766.                  (or (not (string= string completion))
  767.                  (file-exists-p completion)))
  768.             completion))
  769.         (error nil)))))
  770.       (progn
  771.     (funcall cmd)
  772.     nil)
  773.       t))
  774.  
  775. ;;;
  776. (defun completer-minibuf (&optional mode)
  777.   "Partial completion of minibuffer expressions.  Optional MODE is
  778. 'help for help and 'exit for exit.
  779.  
  780. If what has been typed so far matches any possibility normal
  781. completion will be done.  Otherwise, the string is considered to be a
  782. pattern with words delimited by the characters in
  783. completer-words.  If completer-exact is T, the best match will be
  784. the shortest one with the same number of words as the pattern if
  785. possible and otherwise the shortest matching expression.  If called
  786. with a prefix, caching will be temporarily disabled.
  787.  
  788. Examples:
  789. a-f     auto-fill-mode
  790. r-e     rmail-expunge
  791. b--d    *begining-of-defun or byte-recompile-directory
  792. by  d   *byte-recompile-directory if completer-any-delimiter is \" \"
  793. ~/i.e   *~/ilisp.el or ~/il-el.el or ~/ilisp.elc
  794. /u/mi/  /usr/misc/"
  795.   (interactive)
  796.   (append
  797.    (let ((completer-use-cache (not (or (not completer-use-cache)
  798.                        current-prefix-arg))))
  799.      (completer (completer-minibuf-string)
  800.         minibuffer-completion-table
  801.         minibuffer-completion-predicate
  802.         completer-words
  803.         completer-any-delimiter
  804.         mode))
  805.    (list "^" completer-words mode)))
  806.  
  807. ;;;%%Commands
  808. (defun completer-toggle ()
  809.   "Turn partial completion on or off."
  810.   (interactive)
  811.   (setq completer-disable (not completer-disable))
  812.   (message (if completer-disable 
  813.            "Partial completion OFF"
  814.            "Partial completion ON")))
  815.  
  816. ;;;
  817. (defvar completer-old-help
  818.   (lookup-key minibuffer-local-must-match-map "?")
  819.   "Old binding of ? in minibuffer completion map.")
  820. (defun completer-help ()
  821.   "Partial completion minibuffer-completion-help.  
  822. See completer-minibuf for more information."
  823.   (interactive)
  824.   (if (completer-new-cmd completer-old-help)
  825.       (apply 'completer-goto (completer-minibuf 'help))))
  826.  
  827. ;;;
  828. (defvar completer-old-completer
  829.   (lookup-key minibuffer-local-must-match-map "\t")
  830.   "Old binding of TAB in minibuffer completion map.")
  831. (defun completer-complete ()
  832.   "Partial completion minibuffer-complete.
  833. See completer-minibuf for more information."
  834.   (interactive)
  835.   (if (completer-new-cmd completer-old-completer)
  836.       (apply 'completer-goto (completer-minibuf))))
  837.  
  838. ;;;
  839. (defvar completer-old-word
  840.   (lookup-key minibuffer-local-must-match-map " ")
  841.   "Old binding of SPACE in minibuffer completion map.")
  842. (defun completer-word ()
  843.   "Partial completion minibuffer-complete.
  844. See completer-minibuf for more information."
  845.   (interactive)
  846.   (if (eq completer-any-delimiter ?\ )
  847.       (insert ?\ )
  848.       (if (completer-new-cmd completer-old-word)
  849.       (apply 'completer-goto (completer-minibuf)))))
  850.  
  851. ;;; 
  852. (defvar completer-old-exit
  853.   (lookup-key minibuffer-local-must-match-map "\n")
  854.   "Old binding of RET in minibuffer completion map.")
  855. (defun completer-exit ()
  856.   "Partial completion minibuffer-complete-and-exit.
  857. See completer-minibuf for more information."
  858.   (interactive)
  859.   (if (completer-new-cmd completer-old-exit)
  860.       (let* ((completions (completer-minibuf 'exit))
  861.          (match (car completions))
  862.          (unique-p (car (cdr (cdr (cdr completions))))))
  863.     (apply 'completer-goto completions)
  864.     (if unique-p
  865.         (completer-minibuf-exit)
  866.         (if match
  867.         (progn (completer-insert match "^")
  868.                (if minibuffer-completion-confirm
  869.                (completer-message " (Confirm)")
  870.                (completer-minibuf-exit)))
  871.         (if (not completer-message) (beep)))))))
  872.  
  873. ;;;
  874. (defun completer-match-exit ()
  875.   "Exit the minibuffer with the current best match."
  876.   (interactive)
  877.   (let* ((completions (completer-minibuf 'exit))
  878.      (guess (car completions)))
  879.     (if (not guess) 
  880.     ;; OK if last filename component doesn't match
  881.     (setq completions (completer-minibuf 'exit-ok)
  882.           guess (car completions)))
  883.     (if guess
  884.     (progn
  885.       (goto-char (point-min))
  886.       (insert guess)
  887.       (delete-region (point) (point-max))
  888.       (exit-minibuffer))
  889.     (apply 'completer-goto completions))))
  890.  
  891. ;;;%%Keymaps
  892. ;this interferes with normal undo.
  893. ;(define-key minibuffer-local-completion-map "\C-_"  'completer-undo)
  894. (define-key minibuffer-local-completion-map "\t"    'completer-complete)
  895. (define-key minibuffer-local-completion-map " "     'completer-word)
  896. (define-key minibuffer-local-completion-map "?"     'completer-help)
  897. (define-key minibuffer-local-completion-map "\n"    'completer-minibuf-exit)
  898. (define-key minibuffer-local-completion-map "\r"    'completer-minibuf-exit)
  899. (define-key minibuffer-local-completion-map "\M-\n" 'completer-match-exit)
  900. (define-key minibuffer-local-completion-map "\M-\r" 'completer-match-exit)
  901.  
  902. ;this interferes with normal undo.
  903. ;(define-key minibuffer-local-must-match-map "\C-_"  'completer-undo)
  904. (define-key minibuffer-local-must-match-map "\t"    'completer-complete)
  905. (define-key minibuffer-local-must-match-map " "     'completer-word)
  906. (define-key minibuffer-local-must-match-map "\n"    'completer-exit)
  907. (define-key minibuffer-local-must-match-map "\r"    'completer-exit)
  908. (define-key minibuffer-local-must-match-map "?"     'completer-help)
  909. (define-key minibuffer-local-must-match-map "\M-\n" 'completer-match-exit)
  910. (define-key minibuffer-local-must-match-map "\M-\r" 'completer-match-exit)
  911.  
  912. ;;;%comint 
  913. (defun completer-comint-dynamic-list-completions (completions)
  914.   "List in help buffer sorted COMPLETIONS.
  915. Typing SPC flushes the help buffer."
  916.   (completer-comint-dynamic-complete-1 nil 'help))
  917.  
  918. (defun completer-comint-dynamic-complete-filename ()
  919.   "Dynamically complete the filename at point."
  920.   (interactive)
  921.   (completer-comint-dynamic-complete-1 nil t))
  922.  
  923. ;;;
  924. (defun completer-comint-dynamic-complete-1 (&optional undo mode)
  925.   "Complete the previous filename or display possibilities if done
  926. twice in a row.  If called with a prefix, undo the last completion."
  927.   (interactive "P")
  928.   (if undo
  929.       (completer-undo)
  930.     ;; added by jwz: don't cache completions in shell buffer!
  931.     (setq completer-string nil)
  932.     (let ((conf (current-window-configuration)));; lemacs change
  933.       (completer-complete-goto 
  934.        "^ \t\n\""
  935.        completer-words
  936.        'read-file-name-internal
  937.        default-directory
  938.        mode)
  939.       ;; lemacs change
  940.       (if (eq mode 'help) (comint-restore-window-config conf))
  941.       )))
  942. ;(fset 'comint-dynamic-complete 'completer-comint-dynamic-complete)
  943. (fset 'comint-dynamic-complete-filename
  944.       'completer-comint-dynamic-complete-filename)
  945. (fset 'comint-dynamic-list-completions 
  946.       'completer-comint-dynamic-list-completions)
  947.  
  948. ;;; Set the functions again if comint is loaded
  949. (setq comint-load-hook 
  950.       (cons (function (lambda ()
  951. ;;          (fset 'comint-dynamic-complete 
  952. ;;            'completer-comint-dynamic-complete)
  953.             (fset 'comint-dynamic-complete-filename
  954.                   'completer-comint-dynamic-complete-filename)
  955.           (fset 'comint-dynamic-list-completions 
  956.             'completer-comint-dynamic-list-completions)))
  957.         (if (and (boundp 'comint-load-hook) comint-load-hook)
  958.         (if (consp comint-load-hook) 
  959.             (if (eq (car comint-load-hook) 'lambda)
  960.             (list comint-load-hook)
  961.             comint-load-hook)
  962.             (list comint-load-hook)))))
  963.  
  964. ;;;%lisp-complete-symbol
  965. (defun lisp-complete-symbol (&optional mode)
  966.   "Perform partial completion on Lisp symbol preceding point.  That
  967. symbol is compared against the symbols that exist and any additional
  968. characters determined by what is there are inserted.  If the symbol
  969. starts just after an open-parenthesis, only symbols with function
  970. definitions are considered.  Otherwise, all symbols with function
  971. definitions, values or properties are considered.  If called with a
  972. negative prefix, the last completion will be undone."
  973.   (interactive "P")
  974.   (if (< (prefix-numeric-value mode) 0)
  975.       (completer-undo)
  976.       (let* ((end (save-excursion (skip-chars-forward "^ \t\n)]}\"") (point)))
  977.          (beg (save-excursion
  978.             (backward-sexp 1)
  979.             (while (= (char-syntax (following-char)) ?\')
  980.               (forward-char 1))
  981.             (point)))
  982.          (pattern (buffer-substring beg end))
  983.          (predicate
  984.           (if (eq (char-after (1- beg)) ?\()
  985.           'fboundp
  986.           (function (lambda (sym)
  987.             (or (boundp sym) (fboundp sym)
  988.             (symbol-plist sym))))))
  989.          (completion (try-completion pattern obarray predicate)))
  990.        (cond ((eq completion t))
  991.           ((null completion)
  992.            (completer-complete-goto
  993.         "^ \t\n\(\)[]{}'`" completer-words
  994.         obarray predicate 
  995.         nil
  996.         (if (not (eq predicate 'fboundp))
  997.             (function (lambda (choice)
  998.               (if (fboundp (intern choice))
  999.               (list choice " <f>")
  1000.               choice))))))
  1001.           ((not (string= pattern completion))
  1002.            (delete-region beg end)
  1003.            (insert completion))
  1004.           (t
  1005.            (message "Making completion list...")
  1006.            (let ((list (all-completions pattern obarray predicate)))
  1007.          (or (eq predicate 'fboundp)
  1008.              (let (new)
  1009.                (while list
  1010.              (setq new (cons (if (fboundp (intern (car list)))
  1011.                          (list (car list) " <f>")
  1012.                          (car list))
  1013.                      new))
  1014.              (setq list (cdr list)))
  1015.                (setq list (nreverse new))))
  1016.          (with-output-to-temp-buffer "*Help*"
  1017.            (funcall completion-display-completion-list-function
  1018.             (sort list (function (lambda (x y)
  1019.                        (string-lessp
  1020.                         (or (car-safe x) x)
  1021.                         (or (car-safe y) y))))))))
  1022.            (message "Making completion list...%s" "done"))))))
  1023.  
  1024. ;;;%Hooks
  1025. (provide 'completer)
  1026. (run-hooks 'completer-load-hook)
  1027.